﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using Water.Architecture2.EntityXML;
using Water.Resources.Globalize;
using System.Data;

namespace Water.Architecture2.Model
{
    internal class EntityMapping
    {
        #region === 私有字段
        private Dictionary<string, Type> ht_propertiesType = new Dictionary<string, Type>();//存储实体对象类型
        private Dictionary<string, Type> ht_columnsType = new Dictionary<string, Type>();//存储字段对应的实体对象的类型

        //实体配置文件<property name="name" column="unit_name"/>
        private Dictionary<string, string> ht_propertieColumnsMap = new Dictionary<string, string>();//所有引用name和column对应关系
        private Dictionary<string, string> ht_directPropertieColumnsMap = new Dictionary<string, string>();//非引用name和column对应关系
        private Dictionary<string, string> ht_refPropertieColumnsMap = new Dictionary<string, string>();//引用name和column对应关系


        //private  string fields; //存储实体对象的有效字段
        private string allFields;//存储实体对象的所有效字段(配置文件中所有字段)
        //private  List<string> a_fields = new List<string>();
        private List<string> a_allFields = new List<string>();
        private List<string> allPropertitiesList = new List<string>();

        private List<PropertyNode> propertyNodes = new List<PropertyNode>();
        private List<PropertyNode> keyProertyNodes = new List<PropertyNode>();
        private List<PropertyNode> refProertyNodes = new List<PropertyNode>();


        private string table;
        private string view;
        private string sql;
        private bool subquery = false;
        private string primaryKeys;
        private List<string> a_primaryKeys = new List<string>();
        private string defaultOrderByExpress;
        //private  ArrayList updateIgnoreFields = new ArrayList();
        //private  ArrayList insertIgnoreFields = new ArrayList();
        private List<string> updateIgnoreFields = new List<string>();
        private List<string> insertIgnoreFields = new List<string>();

        private string connectionStringName;//数据库连接名
        private bool queryOnly;//是否仅查询

        private string baseQuerySql;

        private Dictionary<string, string> autoGenerators = new Dictionary<string, string>();//自动生成列 目前仅支持oracle sequence


        private string dalClass;
        private string dalAssembly;

        #endregion

        #region Properties
        internal string Table
        {
            get { return this.table; }
            set { this.table = value; }
        }
        internal string View
        {
            get { return this.view; }
            set { this.view = value; }
        }
        internal string Sql
        {
            get { return this.sql; }
            set { this.sql = value; }
        }
        internal bool Subquery
        {
            get { return subquery; }
            set { subquery = value; }
        }
        internal string DefaultOrderByExpress
        {
            get { return this.defaultOrderByExpress; }
            set { this.defaultOrderByExpress = value; }
        }
        internal string ConnectionStringName
        {
            get { return this.connectionStringName; }
            set { this.connectionStringName = value; }
        }
        internal bool QueryOnly
        {
            get { return this.queryOnly; }
            set { this.queryOnly = value; }
        }


        internal List<string> UpdateIgnoreFields
        {
            get { return this.updateIgnoreFields; }
            set { this.updateIgnoreFields = value; }
        }
        internal List<string> InsertIgnoreFields
        {
            get { return this.insertIgnoreFields; }
            set { this.insertIgnoreFields = value; }
        }


        internal string PrimaryKeys
        {
            get { return this.primaryKeys; }
            set { this.primaryKeys = value; }
        }
        internal List<string> PrimaryKeyList
        {
            get { return this.a_primaryKeys; }
            set { this.a_primaryKeys = value; }
        }

        internal string AllFields
        {
            get { return this.allFields; }
            set { this.allFields = value; }
        }

        internal List<string> AllPropertitiesList
        {
            get { return allPropertitiesList; }
            set { allPropertitiesList = value; }
        }
        internal List<string> AllFieldList
        {
            get { return this.a_allFields; }
            set { this.a_allFields = value; }
        }

        internal List<PropertyNode> PropertyNodes
        {
            get { return this.propertyNodes; }
            set { this.propertyNodes = value; }
        }
        internal List<PropertyNode> KeyProertyNodes
        {
            get { return this.keyProertyNodes; }
            set { this.keyProertyNodes = value; }
        }
        internal List<PropertyNode> RefProertyNodes
        {
            get { return this.refProertyNodes; }
            set { this.refProertyNodes = value; }
        }


        internal Dictionary<string,Type> PropertiesType
        {
            get { return this.ht_propertiesType; }
            set { this.ht_propertiesType = value; }
        }
        internal Dictionary<string, Type> ColumnsType
        {
            get { return this.ht_columnsType; }
            set { this.ht_columnsType = value; }
        }
        internal Dictionary<string, string> PropertieColumnsMap
        {
            get { return this.ht_propertieColumnsMap; }
            set { this.ht_propertieColumnsMap = value; }
        }
        internal Dictionary<string, string> DirectPropertieColumnsMap
        {
            get { return this.ht_directPropertieColumnsMap; }
            set { this.ht_directPropertieColumnsMap = value; }
        }
        internal Dictionary<string, string> RefPropertieColumnsMap
        {
            get { return this.ht_refPropertieColumnsMap; }
            set { this.ht_refPropertieColumnsMap = value; }
        }


        internal string BaseQuerySql
        {
            get { return baseQuerySql; }
            set { baseQuerySql = value; }
        }

        internal Dictionary<string, string> AutoGenerators
        {
            get { return autoGenerators; }
            set { autoGenerators = value; }
        }

        internal string DalClass
        {
            get { return dalClass; }
            set { dalClass = value; }
        }

        internal string DalAssembly
        {
            get { return dalAssembly; }
            set { dalAssembly = value; }
        }


        #endregion

        internal void init(EntityNode entityNode)
        {
            this.Table = entityNode.Table;
            this.View = entityNode.View;
            this.sql = entityNode.Sql;
            this.subquery = entityNode.Subquery;
            this.ConnectionStringName = entityNode.ConnectionStringName;
            this.QueryOnly = entityNode.QueryOnly;
            this.DefaultOrderByExpress = entityNode.DefaultOrderByExpress;
           
            this.DalAssembly = entityNode.DalAssembly;

            if (string.IsNullOrEmpty(entityNode.DalClass))
                throw new Exception(string.Format(ExceptionResource.ExceptionEntityAttribute, entityNode.EntityClass, "dal-class"));
            else
                this.DalClass = entityNode.DalClass;

            allFields = string.Empty;
            primaryKeys = string.Empty;

            ht_propertiesType.Clear();
            updateIgnoreFields.Clear();
            insertIgnoreFields.Clear();
            a_allFields.Clear();
            allPropertitiesList.Clear();
            a_primaryKeys.Clear();
            ht_columnsType.Clear();
            ht_propertieColumnsMap.Clear();
            ht_directPropertieColumnsMap.Clear();
            ht_refPropertieColumnsMap.Clear();


            propertyNodes = entityNode.PropertyNodes;
            foreach (PropertyNode propertyNode in propertyNodes)
            {
                string name=string.Empty;
                string column=string.Empty;

                //name attribute must 
                if (null != propertyNode.Name)
                    name = propertyNode.Name.ToUpper();
                else
                    throw new Exception(string.Format(ExceptionResource.ExceptionEntityAttribute, entityNode.EntityClass, "name"));

                //ref-property allow have not column attribute
                if (null != propertyNode.Column && PropertyNodeType.RefProperty != propertyNode.NodeType)
                    column = propertyNode.Column.ToUpper();

                //not ref-property must have a column attribute
                if (string.IsNullOrEmpty(column) && PropertyNodeType.RefProperty != propertyNode.NodeType)
                    throw new Exception(string.Format(ExceptionResource.ExceptionEntityAttribute, entityNode.EntityClass, "column"));


                //type
                try
                {
                    if (PropertyNodeType.RefProperty != propertyNode.NodeType)
                    {
                        Type t = System.Type.GetType(propertyNode.Type);
                        ht_propertiesType.Add(name, t);
                        ht_columnsType.Add(column, t);
                    }
                }
                catch (Exception)
                {
                    throw new Exception(string.Format(ExceptionResource.ExceptionEntityPropertyType, entityNode.EntityClass,name,propertyNode.Type));
                }
                //column
                if (!string.IsNullOrEmpty(column))
                {
                    ht_propertieColumnsMap.Add(name, column);
                    a_allFields.Add(column);
                    allPropertitiesList.Add(name);
                }
                // update-ignore and insert-ingore
                if (PropertyNodeType.RefProperty != propertyNode.NodeType)
                {
                    if (propertyNode.UpdateIgnore)
                        updateIgnoreFields.Add(column);

                    if (propertyNode.InsertIgnore || propertyNode.GeneratorType == GeneratorType.Sequence)
                        insertIgnoreFields.Add(column);
                }

                if (PropertyNodeType.Property == propertyNode.NodeType)
                {
                    this.ht_directPropertieColumnsMap.Add(name, column);
                }
                if (PropertyNodeType.KeyProperty == propertyNode.NodeType)
                {
                    a_primaryKeys.Add(column);
                    keyProertyNodes.Add(propertyNode);
                    this.ht_directPropertieColumnsMap.Add(name, column);
                }

                if (PropertyNodeType.RefProperty == propertyNode.NodeType)
                {
                    refProertyNodes.Add(propertyNode);
                    //this.ht_refPropertieColumnsMap.Add(name, column);
                }

                if (propertyNode.GeneratorType == GeneratorType.Sequence && PropertyNodeType.RefProperty != propertyNode.NodeType)
                    this.autoGenerators.Add(column, propertyNode.GeneratorName);
            }

            allFields = string.Join(",", a_allFields.ToArray());
            primaryKeys = string.Join(",", a_primaryKeys.ToArray());

        }


    }
}
